#include "tcp_client.h"
#include <stdio.h>	
#include <string.h>
#include "lwip/netif.h"
#include "lwip/ip.h"
#include "lwip/tcp.h"
#include "lwip/init.h"
#include "netif/etharp.h"
#include "lwip/udp.h"
#include "lwip/pbuf.h"


struct tcp_pcb *tcp_client_pcb = NULL;

// 出现错误时调用这个函数，打印错误信息，并尝试重新连接
static void tcp_client_error_cb(void *arg, err_t err)       
{
    printf("[%s] L%d : %s connected error %d\r\n", __FILE__, __LINE__, __func__, err);
    // 连接失败的时候释放TCP控制块的内存
    if(tcp_client_pcb)
    {
        tcp_close(tcp_client_pcb);
        tcp_client_pcb = NULL;
    }
    tcp_client_init();

}

// 发送函数，调用了tcp_write函数
static err_t tcp_client_send_cb(void *arg, struct tcp_pcb *tpcb)   
{
    uint8_t send_buf[] = "client send 1 msg";

    tcp_write(tpcb, send_buf, sizeof(send_buf), 1);

    return ERR_OK;
}

static err_t tcp_client_recv_cb(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
{
    if(p != NULL)
    {
        tcp_recved(tpcb, p->tot_len);
        // 回传
        tcp_write(tpcb, p->payload, p->tot_len, 1);

        memset(p->payload, 0, p->tot_len);

        pbuf_free(p); // 必须释放
    }
    else if(err == ERR_OK)
    {
        printf("server offline\r\n");
        // 服务器断开
        tcp_close(tpcb);
        
        tcp_client_init();
    }
    return ERR_OK;
}

static err_t tcp_client_connected_cb(void *arg, struct tcp_pcb *tpcb, err_t err)
{
    printf("client connect ok\r\n");

    // 注册一个周期性回调函数 单位 500ms 2 = 2*500ms = 1s
    tcp_poll(tpcb, tcp_client_send_cb, 2);

    // 注册一个接收函数
    tcp_recv(tpcb, tcp_client_recv_cb);

    return ERR_OK;
}

void tcp_client_init(void)
{
    err_t ret = 0;
    ip4_addr_t tcp_server_ip;
    tcp_client_pcb = tcp_new();

    // 合并IP地址
    IP4_ADDR(&tcp_server_ip, 
        TCP_SERVER_IP_ADDR0, 
        TCP_SERVER_IP_ADDR1, 
        TCP_SERVER_IP_ADDR2,
        TCP_SERVER_IP_ADDR3);

    printf("client connecting\r\n");
    ret = tcp_connect(tcp_client_pcb, &tcp_server_ip, 
        TCP_SERVER_PORT, tcp_client_connected_cb);
    if(ret != ERR_OK)
    {
        printf("client connect error %d\r\n", ret);
    }
    // 注册异常回调
    tcp_err(tcp_client_pcb, tcp_client_error_cb);

}



